package com.telit.communicate.communicate;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.NettyRuntime;
import io.netty.util.ResourceLeakDetector;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


/**
 * @author zhouyu
 * @description netty服务端
 * ********************************** 客户端连接路径 ws://ip:port/forestry/${userId}_${MsgSource}_${SystemName} ***************************
 * ********************************** 如： ws://127.0.0.1:7888/forestry/1_WEB_FIREPROOF **************************************************
 **/
@Component
public class NettyServer {

    @Value("${nettyServer.port}")
    private int port;

    public void startServer() throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workgroup = new NioEventLoopGroup();
        ServerBootstrap sb = new ServerBootstrap();
        //分发线程与io线程分离
        DefaultEventExecutorGroup eventExecutors = new DefaultEventExecutorGroup(NettyRuntime.availableProcessors() * 2);
        sb.group(bossGroup, workgroup)
                .channel(NioServerSocketChannel.class)
                //使用池化buf
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.ALLOCATOR,PooledByteBufAllocator.DEFAULT)
                .localAddress(port)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        //5分钟未进行读写操作触发userEventTriggered事件
                        //ch.pipeline().addLast(new IdleStateHandler(0, 0, 300, TimeUnit.SECONDS));
                        ch.pipeline().addLast(new HttpServerCodec());
                        ch.pipeline().addLast(new ChunkedWriteHandler());
                        ch.pipeline().addLast(new HttpObjectAggregator(1024 * 1024));
                        ch.pipeline().addLast(eventExecutors, new ServerHandler());
                        //使用 WebSocketServerProtocolHandler 的重载构造方法，checkStartsWith = true 表示不用完全匹配/forestry，可以在该路径后添加其他参数
                        ch.pipeline().addLast(new WebSocketServerProtocolHandler("/forestry", null, true, 1024 * 1024, false, true));
                    }
                });
        //内存泄漏检测，生产环境注释该行代码
        ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
        ChannelFuture cf = sb.bind().sync();
        cf.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> {
            bossGroup.shutdownGracefully().sync();
            workgroup.shutdownGracefully().sync();
        });
    }
}
